package com.orifine.orm.model;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import com.orifine.orm.annotation.Column;
import com.orifine.orm.annotation.Table;
import com.orifine.utils.ClassUtils;



public class TableModel {
	private String name;
	private Class<?> tableClass;
	private DatabaseModel database;
	private Map<String, ColumnModel> stringColumnMap = new HashMap<String, ColumnModel>();
	private Map<Field, ColumnModel> fieldColumnMap = new HashMap<Field, ColumnModel>();
	private Set<ColumnModel> columnMap = new HashSet<ColumnModel>();
	
	private Map<String, Set<ColumnModel>> uniqueColumnSets = new HashMap<String, Set<ColumnModel>>();
	private Set<ColumnModel> idColumnSet = new HashSet<ColumnModel>();
	
	private int informationSize;
	
	void init(Class<?> tableClass, DatabaseModel database){
		this.tableClass = tableClass;
		this.database = database;
		
		Table tableAnnotation = tableClass.getAnnotation(Table.class);
		if(tableAnnotation.value().equals("")) {
			name = ClassUtils.convertClassNameToDatabaseName(tableClass.getSimpleName());
		} else {
			name = tableAnnotation.value();
		}
		this.informationSize = tableAnnotation.infomationSize();
	}
	
	private boolean isFirstCallGetColumns = true;
	public Set<ColumnModel> getColumns(){
		if(isFirstCallGetColumns){
			//获取tableClass里面的所有属性成员
			for(Field field : tableClass.getDeclaredFields()){
				//判断属性成员是否静态成员
				if(!Modifier.isStatic(field.getModifiers())) {
					ColumnModel column = getColumn(field);
					if(column != null){
						//UNIQUE
						for(String uniqueString : column.getUnique().getUniques()){
							Set<ColumnModel> columnModelSet = uniqueColumnSets.get(uniqueString);
							if(columnModelSet == null){
								columnModelSet = new HashSet<ColumnModel>();
							}
							columnModelSet.add(column);
						}
						
						//ID
						if(column.getId().getValue()){
							idColumnSet.add(column);
						}
					}
				}
			}
			
			//UNIQUE
			Set<String> removeUniqueColumnMapperSet = new HashSet<String>();//因为Set在循环过程中不能删除和添加，所以需要另外定义一个变量，待循环结速后一次性删除
			for(String uniqueColumnSetKey : uniqueColumnSets.keySet()){
				Set<ColumnModel> uniqueColumnSet = uniqueColumnSets.get(uniqueColumnSetKey);
				if(uniqueColumnSet.size() == 1){
					ColumnModel uniqueColumn = uniqueColumnSet.iterator().next();
					uniqueColumn.getUnique().isUnique(true);
					removeUniqueColumnMapperSet.add(uniqueColumnSetKey);
				} else {
					for(ColumnModel uniqueColumn : uniqueColumnSet){
						uniqueColumn.getUnique().isUnique(false);
					}
				}
			}
			for(String uniqueColumnSetKey : removeUniqueColumnMapperSet){
				uniqueColumnSets.remove(uniqueColumnSetKey);
			}
			
			//ID
			if(idColumnSet.size() == 1){
				ColumnModel idColumn = idColumnSet.iterator().next();
				idColumn.getId().isId(true);
			} else {
				for(ColumnModel idColumn : idColumnSet){
					idColumn.getId().isId(false);
				}
			}
			isFirstCallGetColumns = false;
		}
		return columnMap;
	}
	
	public ColumnModel getColumn(String fieldName) {
		ColumnModel column = stringColumnMap.get(fieldName);
		if(column != null){
			return column;
		} else {
			return addColumn(fieldName);
		}
	}
	
	public ColumnModel getColumn(Field field){
		ColumnModel column = fieldColumnMap.get(field);
		if(column != null){
			return column;
		} else {
			return addColumn(field);
		}
	}
	
	private ColumnModel addColumn(String fieldName){
		Field field = null;
		try {
			field = tableClass.getDeclaredField(fieldName);
		} catch (SecurityException e) {
			throw new RuntimeException(e.getMessage(), e.fillInStackTrace());
		} catch (NoSuchFieldException e) {
		}
		if(field != null){
			return addColumn(field);
		} else {
			return null;
		}
	}
	
	private ColumnModel addColumn(Field field){
		if(Modifier.isStatic(field.getModifiers())){
			return null;
		}
		Column columnAnnotation = field.getAnnotation(Column.class);
		if(columnAnnotation != null){
			ColumnModel column = null;
			try {
				column = (ColumnModel)tableClass.getDeclaredField(COLUMN + ClassUtils.getUpperName(field.getName())).get(null);
			} catch (SecurityException e) {
			} catch (NoSuchFieldException e) {
			} catch (IllegalArgumentException e) {
			} catch (IllegalAccessException e) {
			} catch (ClassCastException e){
			}
			if(column == null){
				column = new ColumnModel();
			}
			stringColumnMap.put(field.getName(), column);
			fieldColumnMap.put(field, column);
			columnMap.add(column);
			column.init(field, this);
			return column;
		} else {
			return null;
		}
	}
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Class<?> getTableClass() {
		return tableClass;
	}

	public void setTableClass(Class<?> tableClass) {
		this.tableClass = tableClass;
	}
	
	public DatabaseModel getDatabase() {
		return database;
	}

	public Map<String, Set<ColumnModel>> getUniqueColumnSets() {
		return uniqueColumnSets;
	}

	public Set<ColumnModel> getIdColumnSet() {
		return idColumnSet;
	}

	public int getInformationSize() {
		return informationSize;
	}

	public static final String COLUMN = "column";
}
